home *** CD-ROM | disk | FTP | other *** search
/ MaxiMac 2000 December / MaxiMac 109.iso / Macworld on CD n°109 / Applications (Mac OS X PB) / MacOSX ScreenSavers / Source Code / Superquadrics / superquadrics.c < prev   
Encoding:
C/C++ Source or Header  |  2000-10-02  |  18.6 KB  |  726 lines  |  [????/????]

  1. /* -*- Mode: C; tab-width: 4 -*- */
  2. /* superquadrics --- 3D mathematical shapes */
  3.  
  4. /*-
  5.  * Permission to use, copy, modify, and sq_distribute this software and its
  6.  * documentation for any purpose and without fee is hereby granted,
  7.  * provided that the above copyright notice appear in all copies and that
  8.  * both that copyright notice and this permission notice appear in
  9.  * supporting documentation.
  10.  *
  11.  * This file is provided AS IS with no warranties of any kind.  The author
  12.  * shall have no liability with respect to the infringement of copyrights,
  13.  * trade secrets or any patents by this file or any part thereof.  In no
  14.  * event will the author be liable for any lost revenue or profits or
  15.  * other special, indirect and consequential damages.
  16.  *
  17.  * Superquadrics were invented by Dr. Alan Barr of Caltech University.
  18.  * They were first published in "Computer Graphics and Applications",
  19.  * volume 1, number 1, 1981, in the article "Superquadrics and Angle-
  20.  * Preserving Transformations."  Dr. Barr based the Superquadrics on
  21.  * Piet Hein's "super ellipses."  Super ellipses are like 2D ellipses,
  22.  * except that the formula includes an exponent, raising its X and Y
  23.  * values to a (fractional) power, and allowing them to gradually
  24.  * change from round to square edges.  Superquadrics extend this
  25.  * idea into 3 dimensions, using two exponents to modify a
  26.  * quadric surface in a similar fashion.
  27.  *
  28.  * Revision History:
  29.  * 30-Mar-97: Turned into a module for xlockmore 4.02 alpha.  The code
  30.  *    is almost unrecognizable now from the first revision, except for
  31.  *    a few remaining two-letter variable names.  I still don't have
  32.  *    the normal vectors working right (I wrote the buggy normal vector
  33.  *    code myself, can you tell?)
  34.  * 07-Jan-97: A legend reborn; Superquadrics make an appearance as a
  35.  *    real OpenGL program written in C.  I can even render them with
  36.  *    proper lighting and specular highlights.  Gee, they look almost
  37.  *    as good now as the original color plates of them that my uncle
  38.  *    showed me as a child in 1981.  I don't know what computer hardware
  39.  *    he was using at the time, but it's taken a couple decades for the
  40.  *    PC clone hardware to catch up to it.
  41.  * 05-Jan-97: After almost a decade, Superquadrics had almost faded away
  42.  *    into the myths and folklore of all the things my brother and I played
  43.  *    with on computers when we were kids with too much time on our hands.
  44.  *    I had since gotten involved in Unix, OpenGL, and other things.
  45.  *    A sudden flash of inspiration caused me to dig out the old Pascal
  46.  *    source code, run it through p2c, and start ripping away the old
  47.  *    sq_wireframe rendering code, to be replaced by OpenGL.
  48.  * Late 1989 or early 1990:  Around this time I did the Turbo Pascal
  49.  *    port of the Superquadrics.  Unfortunately, many of the original variable
  50.  *    names remained the same from the C= 64 original.  This was unfortunate
  51.  *    because BASIC on the c64 only allowed 2-letter, global variable names.
  52.  *    But the speed improvement over BASIC was very impressive at the time.
  53.  * Thanksgiving, 1987: Written.  My uncle Al, who invented Superquadrics some
  54.  *    years earlier, came to visit us.  I was a high school kid at the time,
  55.  *    with nothing more than a Commodore 64.  Somehow we wrote this program,
  56.  *    (he did the math obviously, I just coded it into BASIC for the c64).
  57.  *    Yeah, 320x200 resolution, colorless white sq_wireframe, and half an hour
  58.  *    rendering time per superquadric.  PLOT x,y.  THOSE were the days.
  59.  *    In the following years I would port Superquadrics to AppleBASIC,
  60.  *    AmigaBASIC, and then Turbo Pascal for IBM clones.  5 minutes on a 286!
  61.  *    Talk about fast rendering!  But these days, when my Pentium 166 runs
  62.  *    the same program, the superquadric will already be waiting on the
  63.  *    screen before my monitor can change frequency from text to graphics
  64.  *    mode.  Can't time the number of minutes that way!  Darn ;)
  65.  *
  66.  * Ed Mackey
  67.  */
  68.  
  69. /*-
  70.  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
  71.  * otherwise caddr_t is not defined correctly
  72.  */
  73.  
  74. # define PROGCLASS                    "Superquadrics"
  75. # define HACK_INIT                    init_superquadrics
  76. # define HACK_DRAW                    draw_superquadrics
  77. # define DEFAULTS    "*delay:        100     \n"            \
  78.                     "*count:        25      \n"            \
  79.                     "*cycles:        40      \n"            \
  80.                     "*sq_wireframe:    False    \n"
  81. /*-
  82.  * Note for low-CPU-speed machines:  If your frame rate is so low that
  83.  * attempts at animation appear futile, try using "-cycles 1", which puts
  84.  * Superquadrics into kind of a slide-show mode.  It will still use up
  85.  * all of your CPU power, but it may look nicer.
  86.  */
  87.  
  88. #define DEF_SPINSPEED  "5.0"
  89.  
  90. /* static XrmOptionDescRec opts[] =
  91. {
  92.   {"-spinspeed", ".superquadrics.spinspeed", XrmoptionSepArg, (caddr_t) NULL}
  93. };
  94. static argtype vars[] =
  95. {
  96.   {(caddr_t *) & spinspeed, "spinspeed", "Spinspeed", DEF_SPINSPEED, t_Float}
  97. };
  98. static OptionStruct desc[] =
  99. {
  100.     {"-spinspeed num", "speed of rotation, in degrees per frame"}
  101. };
  102.  
  103. ModeSpecOpt superquadrics_opts =
  104. {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
  105.  
  106. #ifdef USE_MODULES
  107. ModStruct   superquadrics_description =
  108. {"superquadrics", "init_superquadrics", "draw_superquadrics", "release_superquadrics",
  109.  "refresh_superquadrics", "init_superquadrics", NULL, &superquadrics_opts,
  110.  1000, 25, 40, 1, 4, 1.0, "",
  111.  "Shows 3D mathematical shapes", 0, NULL};
  112.  
  113. #endif
  114. */
  115.  
  116. #include <OpenGL/glu.h>
  117. #include <bsd/stdlib.h>
  118. #include <bsd/math.h>
  119.  
  120. #define MaxRes          50
  121. #define MinRes          5
  122.  
  123. typedef double dimi[MaxRes + 1];
  124.  
  125. #define Bool int
  126. #define LRAND random
  127. #define MAXRAND RAND_MAX
  128.  
  129. static void reshape_superquadrics(int x, int y);
  130.  
  131. typedef struct {
  132.     double      xExponent, yExponent;
  133.     GLfloat     r[4], g[4], b[4];
  134.     long        Mode;
  135.     int         sq_rotx, sq_rotz;
  136. } state;
  137.  
  138.     int         sq_dist, sq_wireframe, sq_flatshade, shownorms, maxcount, maxwait;
  139.     int         sq_counter, viewcount, viewwait, sq_mono;
  140.     GLfloat     curmat[4][4], sq_rotx, sq_roty, sq_rotz, spinspeed;
  141.     /* In dimi: the first letter stands for cosine/sine, the second
  142.      *          stands for North, South, East, or West.  I think.
  143.      */
  144.     dimi        cs, se, sw, sn, ss, ce, cw, cn, Prevxx, Prevyy, Prevzz,
  145.                 Prevxn, Prevyn, Prevzn;
  146.     double      xExponent, yExponent, Mode;
  147.     int         resolution;
  148.     state       now, later;
  149.  
  150. #define CLIP_NORMALS 10000.0
  151.  
  152. static int
  153. myrand(int range)
  154. {
  155.     return ((int) (((float) range) * LRAND() / (MAXRAND)));
  156. }
  157.  
  158. static float
  159. myrandreal(void)
  160. {
  161.     return (LRAND() / (MAXRAND));
  162. }
  163.  
  164. /* Some old, old, OLD code follows.  Ahh this takes me back..... */
  165.  
  166. /* Output from p2c, the Pascal-to-C translator */
  167. /* From input file "squad.pas" */
  168.  
  169. static double
  170. XtoY(double x, double y)
  171. {
  172.     double      z, a;
  173.  
  174.     /* This is NOT your typical raise-X-to-the-Y-power function.  Do not attempt
  175.      * to replace this with a standard exponent function.  If you must, just
  176.      * replace the "a = exp(y * log(z));" line with something faster.
  177.      */
  178.  
  179.     z = fabs(x);
  180.     if (z < 1e-20) {
  181.         a = 0.0;
  182.         return a;
  183.     }
  184.     a = exp(y * log(z));
  185.     if (a > CLIP_NORMALS)
  186.         a = CLIP_NORMALS;
  187.     if (x < 0)
  188.         a = -a;
  189.     return a;
  190. }
  191.  
  192.  
  193. static double
  194. Sine(double x, double e)
  195. {
  196.     /* This is just the sine wave raised to the exponent.  BUT, you can't
  197.      * raise negative numbers to fractional exponents.  So we have a special
  198.      * XtoY routune which handles it in a way useful to superquadrics.
  199.      */
  200.  
  201.     return (XtoY(sin(x), e));
  202. }
  203.  
  204.  
  205. static double
  206. Cosine(double x, double e)
  207. {
  208.     return (XtoY(cos(x), e));
  209. }
  210.  
  211.  
  212. static void
  213. MakeUpStuff(int allstuff)
  214. {
  215.     static int  pats[4][4] =
  216.     {
  217.         {0, 0, 0, 0},
  218.         {0, 1, 0, 1},
  219.         {0, 0, 1, 1},
  220.         {0, 1, 1, 0}
  221.     };
  222.  
  223.     int         dostuff;
  224.     int         t, pat;
  225.     GLfloat     r, g, b, r2, g2, b2;
  226.  
  227.     /* randomize it. */
  228.  
  229.     if (maxcount < 2)
  230.         allstuff = 1;
  231.     dostuff = allstuff * 15;
  232.     if (!dostuff) {
  233.         dostuff = myrand(3) + 1;
  234.         if (myrand(2) || (dostuff & 1))
  235.             dostuff |= 4;
  236.         if (myrand(2))
  237.             dostuff |= 8;
  238.     }
  239.     if (dostuff & 1) {
  240.         later.xExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
  241.         later.yExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
  242.  
  243.         /* Increase the 2.0 .. 2.5 range to 2.0 .. 3.0 */
  244.         if (later.xExponent > 2.0)
  245.             later.xExponent = (later.xExponent * 2.0) - 2.0;
  246.         if (later.yExponent > 2.0)
  247.             later.yExponent = (later.yExponent * 2.0) - 2.0;
  248.     }
  249.     if (dostuff & 2) {
  250.         do {
  251.             later.Mode = myrand(3L) + 1;
  252.         } while (!allstuff && (later.Mode == now.Mode));
  253.         /* On init: make sure it can stay in mode 1 if it feels like it. */
  254.     }
  255.     if (dostuff & 4) {
  256.         if (sq_mono) {
  257.             if (sq_wireframe) {
  258.                 b = g = r = 1.0;
  259.                 b2 = g2 = r2 = 1.0;
  260.             } else {
  261.                 b = g = r = (GLfloat) (140 + myrand(100)) / 255.0;
  262.                 b2 = g2 = r2 = ((r > 0.69) ? (1.0 - r) : r);
  263.             }
  264.         } else {
  265.             r = (GLfloat) (40 + myrand(200)) / 255.0;
  266.             g = (GLfloat) (40 + myrand(200)) / 255.0;
  267.             b = (GLfloat) (40 + myrand(200)) / 255.0;
  268.  
  269.             r2 = ((myrand(4) && ((r < 0.31) || (r > 0.69))) ? (1.0 - r) : r);
  270.             g2 = ((myrand(4) && ((g < 0.31) || (g > 0.69))) ? (1.0 - g) : g);
  271.             b2 = ((myrand(4) && ((b < 0.31) || (b > 0.69))) ? (1.0 - b) : b);
  272.         }
  273.  
  274.         pat = myrand(4);
  275.         for (t = 0; t < 4; ++t) {
  276.             later.r[t] = pats[pat][t] ? r : r2;
  277.             later.g[t] = pats[pat][t] ? g : g2;
  278.             later.b[t] = pats[pat][t] ? b : b2;
  279.         }
  280.     }
  281.     if (dostuff & 8) {
  282.         later.sq_rotx = myrand(360) - 180;
  283.         later.sq_rotz = myrand(160) - 80;
  284.     }
  285. }
  286.  
  287. static void
  288. inputs()
  289. {
  290.     int         iv;
  291.     double      u, v, mode3, cn3, inverter2, flatu, flatv;
  292.  
  293.     if (Mode < 1.000001) {
  294.         mode3 = 1.0;
  295.         cn3 = 0.0;
  296.         inverter2 = 1.0;
  297.     } else if (Mode < 2.000001) {
  298.         mode3 = 1.0;
  299.         cn3 = (Mode - 1.0) * 1.5;
  300.         inverter2 = (Mode - 1.0) * -2.0 + 1.0;
  301.     } else {
  302.         mode3 = (Mode - 1.0);
  303.         cn3 = (Mode - 2.0) / 2.0 + 1.5;
  304.         inverter2 = -1.0;
  305.     }
  306.  
  307.     if (sq_flatshade) {
  308.         flatu = M_PI / (resolution - 1);
  309.         flatv = mode3 * M_PI / ((resolution - 1) * 2);
  310.     } else {
  311.         flatu = flatv = 0.0;
  312.     }
  313.  
  314.     /* (void) printf("Calculating....\n"); */
  315.     for (iv = 1; iv <= resolution; iv++) {
  316.  
  317.         /* u ranges from PI down to -PI */
  318.         u = (1 - iv) * 2 * M_PI / (resolution - 1) + M_PI;
  319.  
  320.         /* v ranges from PI/2 down to -PI/2 */
  321.         v = (1 - iv) * mode3 * M_PI / (resolution - 1) + M_PI * (mode3 / 2.0);
  322.  
  323.         /* Use of xExponent */
  324.         se[iv] = Sine(u, xExponent);
  325.         ce[iv] = Cosine(u, xExponent);
  326.         sn[iv] = Sine(v, yExponent);
  327.         cn[iv] = Cosine(v, yExponent) * inverter2 + cn3;
  328.  
  329.         /* Normal vector computations only */
  330.         sw[iv] = Sine(u + flatu, 2 - xExponent);
  331.         cw[iv] = Cosine(u + flatu, 2 - xExponent);
  332.         ss[iv] = Sine(v + flatv, 2 - yExponent) * inverter2;
  333.         cs[iv] = Cosine(v + flatv, 2 - yExponent);
  334.     }            /* next */
  335.  
  336.     /* Now fix up the endpoints */
  337.     se[resolution] = se[1];
  338.     ce[resolution] = ce[1];
  339.  
  340.     if (Mode > 2.999999) {
  341.         sn[resolution] = sn[1];
  342.         cn[resolution] = cn[1];
  343.     }
  344. }
  345.  
  346.  
  347. static void
  348. DoneScale()
  349. {
  350.     double      xx, yy, zz, xp = 0, yp = 0, zp = 0, xn, yn, zn, xnp = 0,
  351.                 ynp = 0, znp = 0;
  352.     int         ih, iv;
  353.  
  354.     /* Hey don't knock my 2-letter variable names.  Simon's BASIC rules, man! ;-> */
  355.     /* Just kidding..... */
  356.     int         toggle = 0;
  357.  
  358.     for (ih = 1; ih <= resolution; ih++) {
  359.         toggle ^= 2;
  360.         for (iv = 1; iv <= resolution; iv++) {
  361.             toggle ^= 1;
  362.             if (sq_wireframe)
  363.                 glColor3f(curmat[toggle][0], curmat[toggle][1], curmat[toggle][2]);
  364.             else
  365.                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, curmat[toggle]);
  366.  
  367.             xx = cn[iv] * ce[ih];
  368.             zz = cn[iv] * se[ih];
  369.             yy = sn[iv];
  370.  
  371.             if (sq_wireframe) {
  372.                 if ((ih > 1) || (iv > 1)) {
  373.                     glBegin(GL_LINES);
  374.                     if (ih > 1) {
  375.                         glVertex3f(xx, yy, zz);
  376.                         glVertex3f(Prevxx[iv], Prevyy[iv], Prevzz[iv]);
  377.                     }
  378.                     if (iv > 1) {
  379.                         glVertex3f(xx, yy, zz);
  380.                         glVertex3f(Prevxx[iv - 1], Prevyy[iv - 1], Prevzz[iv - 1]);
  381.                     }
  382. /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
  383.    * MesaGL 2.2 and -sq_mono.  This has been fixed in MesaGL 2.3 and later. */
  384.                     glEnd();
  385.                 }
  386.             } else {
  387.                 if ((cs[iv] > 1e+10) || (cs[iv] < -1e+10)) {
  388.                     xn = cs[iv];
  389.                     zn = cs[iv];
  390.                     yn = ss[iv];
  391.                 } else {
  392.                     xn = cs[iv] * cw[ih];
  393.                     zn = cs[iv] * sw[ih];
  394.                     yn = ss[iv];
  395.                 }
  396.                 if ((ih > 1) && (iv > 1)) {
  397.                     glNormal3f(xn, yn, zn);
  398.                     glBegin(GL_POLYGON);
  399.                     glVertex3f(xx, yy, zz);
  400.                     if (!sq_flatshade)
  401.                         glNormal3f(Prevxn[iv], Prevyn[iv], Prevzn[iv]);
  402.                     glVertex3f(Prevxx[iv], Prevyy[iv], Prevzz[iv]);
  403.                     if (!sq_flatshade)
  404.                         glNormal3f(xnp, ynp, znp);
  405.                     glVertex3f(xp, yp, zp);
  406.                     if (!sq_flatshade)
  407.                         glNormal3f(Prevxn[iv - 1], Prevyn[iv - 1], Prevzn[iv - 1]);
  408.                     glVertex3f(Prevxx[iv - 1], Prevyy[iv - 1], Prevzz[iv - 1]);
  409.                     glEnd();
  410.                 }
  411.                 if (shownorms) {
  412.                     if (!sq_flatshade)
  413.                         glShadeModel(GL_FLAT);
  414.                     glDisable(GL_LIGHTING);
  415.                     glBegin(GL_LINES);
  416.                     glVertex3f(xx, yy, zz);
  417.                     glVertex3f(xx + xn, yy + yn, zz + zn);
  418.                     glEnd();
  419.                     if (!sq_flatshade)
  420.                         glShadeModel(GL_SMOOTH);
  421.                     glEnable(GL_LIGHTING);
  422.                 }
  423.                 xnp = Prevxn[iv];
  424.                 ynp = Prevyn[iv];
  425.                 znp = Prevzn[iv];
  426.                 Prevxn[iv] = xn;
  427.                 Prevyn[iv] = yn;
  428.                 Prevzn[iv] = zn;
  429.             }
  430.  
  431.             xp = Prevxx[iv];
  432.             yp = Prevyy[iv];
  433.             zp = Prevzz[iv];
  434.             Prevxx[iv] = xx;
  435.             Prevyy[iv] = yy;
  436.             Prevzz[iv] = zz;
  437.  
  438.         }        /* next */
  439.     }            /* next */
  440. }
  441.  
  442. /**** End of really old code ****/
  443.  
  444. static void
  445. SetCull(int init)
  446. {
  447.     static int  cullmode;
  448.  
  449.     if (init) {
  450.         cullmode = 0;
  451.         return;
  452.     }
  453.     if (Mode < 1.0001) {
  454.         if (cullmode != 1) {
  455.             glEnable(GL_CULL_FACE);
  456.             glCullFace(GL_BACK);
  457.             cullmode = 1;
  458.         }
  459.     } else if (Mode > 2.9999) {
  460.         if (cullmode != 2) {
  461.             glEnable(GL_CULL_FACE);
  462.             glCullFace(GL_FRONT);
  463.             cullmode = 2;
  464.         }
  465.     } else {
  466.         if (cullmode) {
  467.             glDisable(GL_CULL_FACE);
  468.             cullmode = 0;
  469.         }
  470.     }
  471. }
  472.  
  473. static void
  474. SetCurrentShape()
  475. {
  476.     int         t;
  477.  
  478.     xExponent = now.xExponent = later.xExponent;
  479.     yExponent = now.yExponent = later.yExponent;
  480.  
  481.     for (t = 0; t < 4; ++t) {
  482.         curmat[t][0] = now.r[t] = later.r[t];
  483.         curmat[t][1] = now.g[t] = later.g[t];
  484.         curmat[t][2] = now.b[t] = later.b[t];
  485.     }
  486.  
  487.     Mode = (double) (now.Mode = later.Mode);
  488.     sq_rotx = now.sq_rotx = later.sq_rotx;
  489.     sq_rotz = now.sq_rotz = later.sq_rotz;
  490.  
  491.     sq_counter = -maxwait;
  492.  
  493.     inputs();
  494. }
  495.  
  496. static void
  497. NextSuperquadric()
  498. {
  499.     double      fnow, flater;
  500.     int         t;
  501.  
  502.     sq_roty -= spinspeed;
  503.     while (sq_roty >= 360.0)
  504.         sq_roty -= 360.0;
  505.     while (sq_roty < 0.0)
  506.         sq_roty += 360.0;
  507.  
  508.     --viewcount;
  509.  
  510.     if (sq_counter > 0) {
  511.         if (--sq_counter == 0) {
  512.             SetCurrentShape();
  513.             if (sq_counter == 0) {        /* Happens if maxwait == 0 */
  514.                 MakeUpStuff(0);
  515.                 sq_counter = maxcount;
  516.             }
  517.         } else {
  518.             fnow = (double) sq_counter / (double) maxcount;
  519.             flater = (double) (maxcount - sq_counter) / (double) maxcount;
  520.             xExponent = now.xExponent * fnow + later.xExponent * flater;
  521.             yExponent = now.yExponent * fnow + later.yExponent * flater;
  522.  
  523.             for (t = 0; t < 4; ++t) {
  524.                 curmat[t][0] = now.r[t] * fnow + later.r[t] * flater;
  525.                 curmat[t][1] = now.g[t] * fnow + later.g[t] * flater;
  526.                 curmat[t][2] = now.b[t] * fnow + later.b[t] * flater;
  527.             }
  528.  
  529.             Mode = (double) now.Mode * fnow + (double) later.Mode * flater;
  530.             sq_rotx = (double) now.sq_rotx * fnow + (double) later.sq_rotx * flater;
  531.             sq_rotz = (double) now.sq_rotz * fnow + (double) later.sq_rotz * flater;
  532.  
  533.             inputs();
  534.         }
  535.     } else {
  536.         if (++sq_counter >= 0) {
  537.             MakeUpStuff(0);
  538.             sq_counter = maxcount;
  539.         }
  540.     }
  541. }
  542.  
  543. static void
  544. DisplaySuperquadrics()
  545. {
  546.     glDrawBuffer(GL_BACK);
  547.     if (sq_wireframe)
  548.         glClear(GL_COLOR_BUFFER_BIT);
  549.     else
  550.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  551.  
  552.     if (viewcount < 1) {
  553.         viewcount = viewwait;
  554.         reshape_superquadrics(-1, -1);
  555.     }
  556.     glPushMatrix();
  557.     glTranslatef(0.0, 0.0, -((GLfloat) (sq_dist) / 16.0) - (Mode * 3.0 - 1.0));    /* viewing transform  */
  558.     glRotatef(sq_rotx, 1.0, 0.0, 0.0);    /* pitch */
  559.     glRotatef(sq_rotz, 0.0, 0.0, 1.0);    /* bank */
  560.     glRotatef(sq_roty, 0.0, 1.0, 0.0);    /* "spin", like heading but comes after P & B */
  561.  
  562.     SetCull(0);
  563.  
  564.     DoneScale();
  565.  
  566.     glPopMatrix();
  567.  
  568.     /* Remember to flush & swap the buffers after calling this function! */
  569. }
  570.  
  571. static void
  572. NextSuperquadricDisplay()
  573. {
  574.     NextSuperquadric();
  575.     DisplaySuperquadrics();
  576. }
  577.  
  578. #define MINSIZE 200
  579. static void
  580. reshape_superquadrics(int w, int h)
  581. {
  582.     static int  last_w = 0, last_h = 0;
  583.     int         maxsize, cursize;
  584.  
  585.     if (w < 0) {
  586.         w = last_w;
  587.         h = last_h;
  588.     } else {
  589.         last_w = w;
  590.         last_h = h;
  591.     }
  592.     maxsize = (w < h) ? w : h;
  593.     if (maxsize <= MINSIZE) {
  594.         cursize = maxsize;
  595.     } else {
  596.         cursize = myrand(maxsize - MINSIZE) + MINSIZE;
  597.     }
  598.     if ((w > cursize) && (h > cursize)) {
  599.         glViewport(myrand(w - cursize), myrand(h - cursize), cursize, cursize);
  600.         w = h = cursize;
  601.     } else {
  602.         glViewport(0, 0, w, h);
  603.     }
  604.     glMatrixMode(GL_PROJECTION);
  605.     glLoadIdentity();
  606.     gluPerspective(30.0, (GLfloat) w / (GLfloat) h, 0.1, 200.0);
  607.     glMatrixMode(GL_MODELVIEW);
  608.     glLoadIdentity();
  609. }
  610.  
  611. static void
  612. InitSuperquadrics(int wfmode, int snorm, int res, int count, float speed)
  613. {
  614.     GLfloat     ambient[] =
  615.     {0.4, 0.4, 0.4, 1.0};
  616.     GLfloat     position[] =
  617.     {10.0, 1.0, 1.0, 10.0};
  618.     GLfloat     mat_diffuse[] =
  619.     {1.0, 0.5, 0.5, 1.0};
  620.     GLfloat     mat_specular[] =
  621.     {0.8, 0.8, 0.8, 1.0};
  622.     GLfloat     mat_shininess[] =
  623.     {50.0};
  624.  
  625.     int         t;
  626.  
  627.     for (t = 0; t < 4; ++t)
  628.         curmat[t][3] = 1.0;
  629.  
  630.     sq_rotx = 35.0;
  631.     sq_roty = 0.0;
  632.     sq_rotz = 0.0;
  633.     sq_dist = 140; //(16 << 3);
  634.     sq_wireframe = sq_flatshade = shownorms = 0;
  635.     maxcount = count;
  636.     if (maxcount < 1)
  637.         maxcount = 1;
  638.     maxwait = maxcount >> 1;
  639.     SetCull(1);
  640.  
  641.     spinspeed = speed;
  642.     viewcount = viewwait = (maxcount < 2) ? 1 : (maxcount << 3);
  643.  
  644.     if (res < MinRes)
  645.         res = MinRes;
  646.     if (res > MaxRes)
  647.         res = MaxRes;
  648.     resolution = res;
  649.  
  650.     if (wfmode == 2)
  651.         sq_flatshade = 1;
  652.     else if (wfmode)
  653.         sq_wireframe = 1;
  654.  
  655.     if (snorm)
  656.         shownorms = 1;
  657.  
  658.     if (sq_wireframe) {
  659.         glShadeModel(GL_FLAT);
  660.         glDisable(GL_LIGHTING);
  661.         glColor3f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2]);
  662.     } else {
  663.         if (sq_flatshade) {
  664.             glShadeModel(GL_FLAT);
  665.             position[0] = 1.0;
  666.             position[3] = 0.0;
  667.         }
  668.         glEnable(GL_LIGHTING);
  669.         glEnable(GL_LIGHT0);
  670.         glDepthFunc(GL_LEQUAL);
  671.         glEnable(GL_DEPTH_TEST);
  672.  
  673.         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  674.         glLightfv(GL_LIGHT0, GL_POSITION, position);
  675.  
  676.         /*glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diffuse); */
  677.         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
  678.         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
  679.  
  680.         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  681.  
  682.         glFrontFace(GL_CW);
  683.         glEnable(GL_NORMALIZE);
  684.     }
  685.  
  686.     MakeUpStuff(1);
  687.     SetCurrentShape();
  688.     MakeUpStuff(1);    /* Initialize it */
  689.     sq_counter = maxcount;
  690. }
  691.  
  692. /* End of superquadrics main functions */
  693.  
  694. void
  695. init_superquadrics()
  696. {
  697.     sq_mono = 0;
  698.  
  699.     //InitSuperquadrics(MI_IS_WIREFRAME(mi), 0,
  700.     //          MI_COUNT(mi), MI_CYCLES(mi), spinspeed);
  701.     //ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
  702.     InitSuperquadrics(sq_wireframe,0,25,40,spinspeed);
  703.     DisplaySuperquadrics();
  704.     glFinish();
  705. }
  706.  
  707. void
  708. draw_superquadrics()
  709. {
  710.  
  711.     NextSuperquadricDisplay();
  712.  
  713.     glFinish();
  714. }
  715.  
  716. void
  717. refresh_superquadrics()
  718. {
  719.     /* Nothing happens here */
  720. }
  721.  
  722. void
  723. release_superquadrics()
  724. {
  725. }
  726.